#include "LCommon.h"

CThreadPool ThreadPool;

void CControlInterface::FreezeThread()
{
	if(m_threadid != GetCurrentThreadId())
		return;
	SuspendThread(hThread);
}

void CControlInterface::RestartThread()
{
	if(m_threadid == GetCurrentThreadId())
		return;
	ResumeThread(hThread);
}

CThreadPool::CThreadPool()
{
}

void CThreadPool::ExecuteTask(CThread* tr)
{
	if(m_freethreads.size())
	{
		Thread* t = *m_freethreads.begin();
		t->Execute = tr;
		t->control.RestartThread();
		m_freelock.Acquire();
		m_freethreads.erase(t);
		m_freelock.Release();
		m_activethreads.insert(t);
	}
	else
		StartThread(tr);
}

void CThreadPool::Start()
{
	m_freelock.Acquire();
	for(register ui32 i = 0; i < USABLE_THREADS; ++i)
	{
		m_freethreads.insert(StartThread(NULL));
	}
	m_freelock.Release();
}
static unsigned long WINAPI proc_addr(void* param)
{
	Thread* t = (Thread*)param;
	for( ; ; )
	{
		if(t->Execute != NULL)
		{
			ThreadPool.AddActiveThread(t);
			t->Execute->Loop();
			ThreadPool.RemoveActiveThread(t);
			delete t->Execute;
			if(t->Kill)
				break;
			t->Execute = NULL;
		}
		if(ThreadPool.IsExiting(t))
			break;
		t->control.FreezeThread();
	}
	ThreadPool.RemoveFreeThread(t);
	ExitThread(0);
}

Thread* CThreadPool::StartThread(CThread* execbase)
{
	Thread* t = new Thread();
	t->Execute  = execbase;
	t->Kill = false;
	DWORD id;
	HANDLE hThread = CreateThread(NULL, 0, &proc_addr, (void*)t, 0, &id);
	t->control.m_threadid = id;
	t->control.RegisterThread(hThread);
	return t;
}

void CThreadPool::ShutDown()
{
	set<Thread*>::iterator itr = m_activethreads.begin();
	set<Thread*>::iterator end = m_activethreads.end();
	for( ; itr != end; ++itr)
	{
		m_threadstoexit.insert(*itr);
		(*itr)->Execute->ThreadState = 0;
		(*itr)->Execute = NULL;
		(*itr)->Kill = true;
	}
}

void CThreadPool::RemoveFreeThread(Thread* t)
{
	Log->Notice("ThreadPool", "Thread %u left threadpool", t->control.m_threadid);
	m_freelock.Acquire();
	m_freethreads.erase(t);
	m_freelock.Release();
	if(IsExiting(t))
	{
		m_threadstoexit.erase(t);
	}
}

void CThreadPool::AddActiveThread(Thread* t)
{
	m_activelock.Acquire();
	m_activethreads.insert(t);
	m_activelock.Release();
	m_freelock.Acquire();
	m_freethreads.erase(t);
	m_freelock.Release();
}

void CThreadPool::RemoveActiveThread(Thread* t)
{
	m_activelock.Acquire();
	m_activethreads.erase(t);
	m_activelock.Release();
	m_freelock.Acquire();
	m_freethreads.insert(t);
	m_freelock.Release();
}

void CThreadPool::SanityCheck()
{
	m_freelock.Acquire();
	Log->Notice("ThreadPool", "=====================================");
	Log->Notice("ThreadPool", "|           Sanitycheck:            |");
	Log->Notice("ThreadPool", "|        Free Threads: %02u           |", m_freethreads.size());
	Log->Notice("ThreadPool", "=====================================");
	m_freelock.Release();
}